package login

import (
	"base"
	"center_server/logic/center/api"
	"center_server/logic/game/api"
	"center_server/logic/gate/api"
	. "center_server/logic/internal"
	"center_server/logic/login/api"
	"emma/errors"
	"leaf/gate"
	"proto/base"
	"proto/server/gate"
	"proto/server/login"
	"sort"
)

type loginSystem struct {
	servers map[base.AgentId]*loginServer
}

var system = new(loginSystem)

func init() {
	system.servers = make(map[base.AgentId]*loginServer)
}

func init() {
	login_api.Login = system.Login
}

func init() {
	Skeleton.AfterInit(func() {
		center_api.RegisterHandler(proto_base.Server_LoginServer, system)
	})
}

func (*loginSystem) Login(msg *proto_server_login.Login) (err error) {
	if len(system.servers) < 1 {
		code := int(proto_base.ErrorCode_NotLoginServer)
		err = errors.New(code, "没有可用的登录服务器")
		return
	}

	servers := make([]*loginServer, 0, len(system.servers))
	for _, server := range system.servers {
		servers = append(servers, server)
	}

	sort.Slice(servers, func(i, j int) bool {
		return servers[i].msgCount < servers[j].msgCount
	})

	server := servers[0]
	server.WriteMsg(msg)
	server.msgCount++
	base.Logger.Debug("login system address: %s, send msg: %s", server.RemoteAddr(), msg)

	return
}

func (*loginSystem) onLogin(server *loginServer, msg *proto_server_login.OnLogin) {
	base.Logger.Debug("login system handle on login")
	server.msgCount--

	gateId := base.AgentId(msg.GateId)
	clientId := base.ClientId(msg.ClientId)
	client, exists := gate_api.GetClient(gateId, clientId)
	if !exists {
		return
	}

	code := msg.Code
	defer func() {
		if code != proto_base.ErrorCode_Success {
			msg := new(proto_server_gate.OnLogin)
			msg.Code = code
			gate_api.OnLogin(gateId, clientId, msg)
		}
	}()

	if code == proto_base.ErrorCode_Success {
		if err := game_api.Login(client, msg); err != nil {
			result := base.ParseError(err)
			code = result.Code
			return
		}
	}

	return
}

func (*loginSystem) OnRegister(id base.AgentId, agent gate.Agent, data []byte) (result interface{}) {
	server := new(loginServer)
	server.Agent = agent
	server.id = id
	system.servers[id] = server

	agent.SetUserData(server)

	return
}

func (*loginSystem) OnClose(id base.AgentId, agent gate.Agent) {
	agent.SetUserData(nil)
	delete(system.servers, id)
}
